<?php
/**
 * 过滤器
 * User: wz_zh
 * Date: 2017/7/12
 * Time: 14:34
 */

namespace PKFrame\DataHandler;
defined('PATH_PK') or die();

class Auth
{

    /**
     * URL 安全过滤函数
     * @param $string
     * @return string
     */
    public static function UrlReplace($string): string
    {
        $string = str_replace('%20', '', $string);
        $string = str_replace('%27', '', $string);
        $string = str_replace('%2527', '', $string);
        $string = str_replace('*', '', $string);
        $string = str_replace('"', '&quot;', $string);
        $string = str_replace("'", '', $string);
        $string = str_replace('"', '', $string);
        $string = str_replace(';', '', $string);
        $string = str_replace('<', '&lt;', $string);
        $string = str_replace('>', '&gt;', $string);
        $string = str_replace("{", '', $string);
        $string = str_replace('}', '', $string);
        return str_replace('\\', '', $string);
    }

    public static function checkPHPCode($string)
    {
        // 检查后的字符
        $skipKeys = ['$_SERVER', '$_POST', 'ini_set', 'DOCUMENT_ROOT', 'display_errors', 'eval(', 'fopen',
            'file_put_contents', 'dirname', 'fwrite', 'get_magic_quotes_gpc', 'stripslashes', 'substr(',
            'PATH_TRANSLATED', 'isset', 'set_time_limit', 'phpinfo', 'fputs', 'base64', 'session_start', '$_SESSION',
            'fclose', 'extract(', 'vbscript', 'applet', 'onafterprint', 'onbeforeactivate', 'onafterupdate',
            'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint',
            'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick',
            'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged',
            'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave',
            'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus',
            'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload',
            'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover',
            'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange',
            'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit',
            'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart',
            'onstop', 'onsubmit', 'onunload', 'call_user_func_array'];
        $replace_str = str_replace($skipKeys, '', $string);
        if (strlen($replace_str) != strlen($string)) {
            blackListIP()->WriteNewIP();
            die('auth');
        }
    }

    /**
     * 强化 addslashes 操作，支持对数组解析
     * @param $data
     * @param int $force
     * @return string
     */
    public static function Addslashes($data, int $force = 1): string
    {
        if (is_array($data) && count($data) > 0) {
            $keys = array_keys($data);
            foreach ($keys as $key) {
                $val = $data[$key];
                unset($data[$key]);
                $data[addslashes($key)] = self::Addslashes($val, $force);
            }
        } elseif (!empty($data) && is_string($data)) {
            $data = addslashes($data);
        }
        return $data;
    }

    /**
     * 强化 stripslashes 操作，支持对数组解析
     * @param $data - 需要处理的字符串或数组
     * @return array|string
     */
    public static function Stripslashes($data)
    {
        if (!is_array($data)) {
            return stripslashes($data);
        }
        foreach ($data as $key => $val) {
            $data[$key] = self::Stripslashes($val);
        }
        return $data;
    }

    /**
     * HTML转义字符
     * @param $data
     * @param int|null $flags
     * @return array|string|string[] 返回转义好的字符串
     */
    public static function Htmlspecialchars($data, int $flags = null)
    {
        if (is_array($data) && count($data)) {
            foreach ($data as $key => $val) {
                $data[$key] = self::htmlspecialchars($val, $flags);
            }
        } else {
            if ($flags === NULL) {
                $data = str_replace(
                    ['&', '"', '<', '>'],
                    ['&amp;', '&quot;', '&lt;', '&gt;'], $data);
                $data = str_replace(['ASCII 0x0d', 'ASCII 0x08', 'ASCII 0x0a'], "", $data);
                if (strpos($data, '&amp;#') !== false) {
                    $data = preg_replace('/&amp;((#(\d{3,5}|x[a-fA-F0-9]{4}));)/', '&\\1', $data);
                }
            } else {
                $data = str_replace('\\', '', $data);
                $data = \htmlspecialchars($data, $flags, 'UTF-8');
            }
        }
        return $data;
    }

    /**
     * HTML反转义字符
     * @param $data
     * @return array|string|string[]
     */
    public static function HtmlspecialcharsDeCode($data)
    {
        if (is_array($data) && count($data)) {
            foreach ($data as $key => $val) {
                $data[$key] = self::HtmlspecialcharsDeCode($val);
            }
        } else {
            $data = \htmlspecialchars_decode(\htmlspecialchars_decode($data, ENT_QUOTES), ENT_QUOTES);
            $data = str_replace('&nbsp;', ' ', $data);
        }
        return $data;
    }

    /**
     * 防火墙 - 检查并过滤变量中非法字符
     * @param null $data 要检查的变量
     * @param bool $is_html 是否保留 HTML 标签
     * @return array|mixed|string|string[]|null
     */
    public static function FilterValue($data = null, bool $is_html = FALSE)
    {
        $data = preg_replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/', '', $data);
        if (gettype($data) == "string" && $is_json = JSON::Is($data)) {
            $json_arr = Arrays::ObjectToArray($is_json);
            if (Arrays::Is($json_arr)) {
                foreach ($json_arr as $k => $v) {
                    $json_arr[$k] = JSON::Is($v) == false ? self::filterValue($v, $is_html) : $v;
                }
            }
            return $json_arr;
        } elseif (gettype($data) == "object") {
            return $data;
        } elseif (Arrays::Is($data)) {
            foreach ($data as $k => $v) {
                $data[$k] = self::filterValue($v, $is_html);
            }
            return $data;
        } else {
            if ($is_html) {
                $data = strip_tags($data);
            }
            $data = htmlspecialchars($data, ENT_QUOTES);
            if (!version_compare(PHP_VERSION, '7.4.0', '<')) {
                if (get_magic_quotes_gpc() == FALSE) {
                    $data = self::addslashes($data);
                }
            } elseif (!empty($data)) {
                $data = stripcslashes($data);
            }
            $data = str_replace('){', '){ ', $data);
            $data = str_replace('\\', '', $data);
            return @trim($data);
        }
    }

    /**
     * 字符串加密、解密函数
     * @param string $string 字符串
     * @param bool $operation true为加密，false为解密，可选参数，默认为ENCODE
     * @param string $key 密钥：数字、字母、下划线
     * @param int $expiry 过期时间
     * @return string
     */
    public static function Base64Encode(string $string = '', bool $operation = false, string $key = '', int $expiry = 0): string
    {
        $key_length = 4;
        $fixed_key = hash('md5', $key);
        $eg_is_keys = md5(substr($fixed_key, 16, 16));
        $run_to_key = $operation ? substr(hash('md5', microtime(true)), -$key_length) : substr($string, 0, $key_length);
        $keys = hash('md5', substr($run_to_key, 0, 16) . substr($fixed_key, 0, 16) . substr($run_to_key, 16) . substr($fixed_key, 16));
        $string = $operation ? sprintf('%010d', $expiry ? $expiry + TIMESTAMP : 0) . substr(md5($string . $eg_is_keys), 0, 16) . $string : base64_decode(substr($string, $key_length));
        $result = '';
        $string_length = strlen($string);
        for ($i = 0; $i < $string_length; $i++) {
            $result .= chr(ord($string{$i}) ^ ord($keys{$i % 32}));
        }
        if ($operation) {
            return $run_to_key . str_replace('=', '', base64_encode($result));
        } else {
            if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - TIMESTAMP > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $eg_is_keys), 0, 16)) {
                return substr($result, 26);
            } else {
                return '';
            }
        }
    }

    /**
     * 使用 HMAC 中的 sha256 算法生成带有密钥的哈希值
     * @param string $data 要进行哈希运算的消息
     * @param string $key 使用 HMAC 生成信息摘要时所使用的密钥
     * @return string 生成带有密钥的哈希值
     */
    public static function HmacSha256(string $data = '', string $key = ''): string
    {
        return hash_hmac('sha256', $data, $key, false);
    }

    /**
     * 过滤上传特殊表情符号的
     * @param string $str
     * @return string
     */
    public static function filterEmoji(string $str): string
    {
        preg_match_all('/[\x{4e00}-\x{9fff}\d\w\s[:punct:]]+/u', $str, $result);
        return join('', $result[0]);
    }

}